package state

import (
	"osiris/core/routine"
	"osiris/dto"
	"osiris/errors"
	"osiris/logger"
	"osiris/ocrypto/ecdsa"
)

// RewardTxHandler 执行出块奖励的交易
type RewardTxHandler struct {
	TxData dto.TxData
}

func (txHandler RewardTxHandler) Verify(tries ...interface{}) bool {
	trie := tries[0]
	tempAccountTrie, ok := trie.(*AccountStateTrie)
	if !ok {
		logger.Warn(map[string]interface{}{"[state] [Verify Reward TX]": "unknown trie!"})
		return false
	}

	//检查目的账户地址是否存在
	addrBytes := ecdsa.StrToAccountBytes(txHandler.TxData.ToAddr)
	exist := tempAccountTrie.HasLeaf(addrBytes)
	if !exist {
		logger.Warn(map[string]interface{}{"[state] [Verify Reward TX]": "destination account addr does not exist!"})
		return false
	}

	return true
}

func (txHandler RewardTxHandler) Commit(tries ...interface{}) bool {
	trie := tries[0]
	tempAccountTrie, ok := trie.(*AccountStateTrie)
	if !ok {
		err := &errors.UnknownStateTrieError{}
		logger.Error(map[string]interface{}{"[state] [Verify Reward TX]": err})
		return false
	}

	//修改目的账户状态：加金额
	toAccountAddrBytes := ecdsa.StrToAccountBytes(txHandler.TxData.ToAddr)
	toLeaf, toExist := tempAccountTrie.GetLeaf(toAccountAddrBytes)
	if !toExist {
		logger.Error(map[string]interface{}{"[state] [Commit Reward TX]": "destination account addr does not exist!"})
		return false
	}

	toLeaf.CommitAssetChange(txHandler.TxData.Amount, txHandler.TxData.CoinSince)

	batch := routine.AtomicRoutineBatch{}
	return batch.Add(&AccountCommitRoutine{
		Kvs: []StateKeyValue{{
			Key:  toAccountAddrBytes,
			Leaf: toLeaf,
		}},
		Trie: tempAccountTrie,
	}).Execute()
}

func (txHandler RewardTxHandler) Undo(tries ...interface{}) bool {
	trie := tries[0]
	tempAccountTrie, ok := trie.(*AccountStateTrie)
	if !ok {
		err := &errors.UnknownStateTrieError{}
		logger.Error(map[string]interface{}{"[state] [Undo Reward TX]": err})
		return false
	}

	//修改目的账户状态：减金额
	toAccountAddrBytes := ecdsa.StrToAccountBytes(txHandler.TxData.ToAddr)
	toLeaf, toExist := tempAccountTrie.GetLeaf(toAccountAddrBytes)
	if !toExist {
		logger.Error(map[string]interface{}{"[state] [Undo Reward TX]": "destination account addr does not exist!"})
		return false
	}

	toLeaf.UndoAssetChange(txHandler.TxData.Amount, txHandler.TxData.CoinSince)

	batch := routine.AtomicRoutineBatch{}
	return batch.Add(&AccountCommitRoutine{
		Kvs: []StateKeyValue{{
			Key:  toAccountAddrBytes,
			Leaf: toLeaf,
		}},
		Trie: tempAccountTrie,
	}).Execute()
}
